package photo

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"mall/common/ctxdatax"
	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/resultx"
	"mall/service/backend/common/utils/pointy"
	"mall/service/blog/rpc/blogclient"
	"mall/service/forum/api/internal/lib/userrank"
	"mall/service/forum/api/internal/logic/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/rpc/forumclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetPhotoByIdLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetPhotoByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPhotoByIdLogic {
	return &GetPhotoByIdLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetPhotoByIdLogic) GetPhotoById(req *types.PhotoIdReq) (*types.PhotoPostInfo, error) {
	if req.Id == nil || *req.Id == 0 {
		return nil, resultx.NewErrCode(resultx.FORUM_POST_ID_REQUIRED)
	}

	userId := ctxdatax.GetUserId(l.ctx)
	var preload string = "forumPost:Id,AuthorId,ParentId,Sticky"
	var eagerLoad string = "forumPost:forumMedia"
	preload += "AuthorName,AuthorAvatar,AuthorLevel,Status"
	preload += "CommentStatus,CommentCount,CreatedAt"
	preload += ";forumMedia:Id,Uid,Url,Thumbnail,altText,Order"
	var platformId uint32 = globalkey.ThirdPartyPlatformWechatMini

	res, err := l.svcCtx.ForumRpc.GetPostById(l.ctx, &forumclient.BaseIdReq{
		Id:         req.Id,
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(platformId),
	})
	if err != nil {
		return nil, err
	}

	if res == nil || res.Id == nil || res.ParentId == nil || *res.Id == 0 || *res.ParentId == 0 {
		return nil, resultx.NewErrCode(resultx.FORUM_POST_STATUS_INVALID)
	}

	parent, err := l.getParentPerfume(*res.ParentId)
	if err != nil {
		return nil, err
	}

	var private bool = true
	var skipLevel bool = true
	if res.AuthorId != nil && *res.AuthorId > 0 && *res.AuthorId != userId {
		private = false
		skipLevel = false
	}

	var photos []*types.MediaInfo
	if len(res.Media) > 0 {
		for _, v := range res.Media {
			var url string
			if v.Url != nil && len(*v.Url) > 0 {
				url = *v.Url
			}
			if len(url) == 0 && v.Uri != nil && len(*v.Uri) > 0 {
				url = *v.Uri
			}
			var thumbnail *bool
			if v.Thumbnail != nil {
				thumbnail = pointy.GetPointer(*v.Thumbnail > 0)
			}
			photos = append(photos, &types.MediaInfo{
				Uid:       v.Uid,
				Id:        v.Id,
				Url:       pointy.GetPointer(url),
				Thumbnail: thumbnail,
				AltText:   v.AltText,
				Details:   v.Meta,
				Order:     v.Order,
			})
		}
	}

	var meta []*types.MetaInfo
	if len(res.Meta) > 0 {
		for _, v := range res.Meta {
			if v.Key == nil || v.Value == nil || len(*v.Key) == 0 || len(*v.Value) == 0 {
				continue
			}

			meta = append(meta, &types.MetaInfo{
				Id:    v.Id,
				Key:   pointy.GetPointer(strings.TrimSpace(*v.Key)),
				Value: pointy.GetPointer(strings.TrimSpace(*v.Value)),
			})
		}
	}

	var author *types.AuthorInfo
	if !skipLevel {
		userRankMap := l.getUserRankMap(userId)
		var levelName *string
		var levelUrl *string
		if res.Author != nil && res.Author.Level != nil && *res.Author.Level > 0 {
			if userRank, ok := userRankMap[*res.Author.Level]; ok {
				levelName = userRank.Name
				levelUrl = userRank.MediaUrl
			}
		}
		if res.Author != nil && res.Author.Name != nil {
			var anonymous *bool
			if res.Author.Anonymous != nil {
				anonymous = pointy.GetPointer(*res.Author.Anonymous > 0)
			}
			author = &types.AuthorInfo{
				Id:        res.Author.Id,
				Name:      res.Author.Name,
				Avatar:    res.Author.Avatar,
				Ip:        res.Author.Ip,
				Level:     res.Author.Level,
				Anonymous: anonymous,
				LevelName: levelName,
				LevelUrl:  levelUrl,
			}
		}
	}
	var statusText *string
	if private && res.Status != nil {
		statusText = pointy.GetPointer(util.GetStatusText(int32(*res.Status)))
	}
	var commentStatus *bool
	if res.CommentStatus != nil {
		commentStatus = pointy.GetPointer(*res.CommentStatus > 0)
	}
	var createdAt *string
	if res.CreatedAt != nil && len(*res.CreatedAt) > 0 {
		createdAt = pointy.GetPointer(util.GetTimeFromNow(*res.CreatedAt))
	}

	return &types.PhotoPostInfo{
		Id:            res.Id,
		ParentId:      res.ParentId,
		Parent:        parent,
		Photos:        photos,
		Meta:          meta,
		Status:        res.Status,
		StatusText:    statusText,
		CommentStatus: commentStatus,
		CommentCount:  res.CommentCount,
		Author:        author,
		CreatedAt:     createdAt,
		UpdatedAt:     res.CreatedAt,
	}, nil
}

func (l *GetPhotoByIdLogic) getParentPerfume(id uint64) (*types.KbEntryInfo, error) {
	var preload string = "blogBook:Id,Title,Slug;blogMedia:Id,Uid,Url,Thumbnail;blogBookMeta:year,averageRating;blogBookRelation:brand"
	var eagerLoad string = "blogBook:blogMedia,blogBookMeta,blogBookRelation"
	res, err := l.svcCtx.BlogRpc.BookDetail(l.ctx, &blogclient.BookDetailReq{
		Id:        int64(id),
		Preload:   preload,
		EagerLoad: eagerLoad,
	})
	if err != nil {
		logrus.Info(fmt.Sprintf("GetPostById getParentPerfume err: %+v", err))
		return nil, err
	}

	var media []*types.TmpMediaInfo
	if len(res.Media) > 0 {
		for _, v := range res.Media {
			media = append(media, &types.TmpMediaInfo{
				Uid:       pointy.GetPointer(uint64(v.Uid)),
				Id:        pointy.GetPointer(strconv.FormatInt(int64(v.Id), 10)),
				Url:       pointy.GetPointer(v.Url),
				Thumbnail: pointy.GetPointer(uint32(v.Thumbnail)),
				AltText:   pointy.GetPointer(v.AltText),
				MetaData:  pointy.GetPointer(v.Meta),
				Order:     pointy.GetPointer(uint32(v.Order)),
			})
		}
	}
	var brand []*types.KbEntryInfo
	if len(res.Relations) > 0 {
		for _, v := range res.Relations {
			if v.Section == "brand" {
				brand = append(brand, &types.KbEntryInfo{
					Id:    pointy.GetPointer(uint64(v.Id)),
					Title: pointy.GetPointer(v.Title),
					Slug:  pointy.GetPointer(v.Slug),
				})
			}
		}
	}
	var year *string
	var averageRating *string
	if len(res.Meta) > 0 {
		for _, v := range res.Meta {
			switch v.Key {
			case "year":
				year = pointy.GetPointer(v.Value)
			case "averageRating":
				averageRating = pointy.GetPointer(moneyx.ParseStar(v.Value, 1))
			}
		}
	}

	return &types.KbEntryInfo{
		Id:            pointy.GetPointer(uint64(res.Id)),
		Title:         pointy.GetPointer(res.Title),
		Slug:          pointy.GetPointer(res.Slug),
		Year:          year,
		AverageRating: averageRating,
		Media:         media,
		Brands:        brand,
	}, nil
}

func (l *GetPhotoByIdLogic) getUserRankMap(userId uint64) map[uint32]*types.UserRankInfo {
	userRank := userrank.NewUserRank(l.ctx, l.svcCtx)
	userRankList, err := userRank.List(userId)
	if err != nil {
		logrus.Info(fmt.Sprintf("GetPostList getUserRankMap err: %+v", err))
		return nil
	}

	if len(userRankList) > 0 {
		resp := make(map[uint32]*types.UserRankInfo)
		for _, v := range userRankList {
			if v.Id != nil && *v.Id > 0 {
				resp[uint32(*v.Id)] = v
			}
		}

		return resp
	}

	return nil
}
